﻿
namespace Sai.Core
{
    using System;

    [Serializable]
    public sealed class UnaryTypeChange : IDiscoveredTypeChange, IEquatable<UnaryTypeChange>
    {
        // required for serialization
        public UnaryTypeChange()
        {
        }

        public UnaryTypeChange(TypeChangeReason reason, string message)
            : this (reason, null, message)
        {
        }

        public UnaryTypeChange(TypeChangeReason reason, IMessageProvider message)
            : this(reason, null, message)
        {
        }

        public UnaryTypeChange(TypeChangeReason reason, ISourceCodeProvider provider)
            : this(reason, provider, string.Empty)
        {
        }

        public UnaryTypeChange(TypeChangeReason reason, ISourceCodeProvider provider, string message)
        {
            this.Reason = reason;
            this.Code = provider == null ? null : provider.ToCode();
            this.Message = message;
        }

        public UnaryTypeChange(TypeChangeReason reason, ISourceCodeProvider provider, IMessageProvider message)
            : this (reason, provider, message.Message)
        {
        }

        public TypeChangeReason Reason { get; set; }

        public SourceCode Code { get; set; }

        public string Message { get; set; }

        public override int GetHashCode()
        {
            if (this.Code == null)
                return this.Reason.GetHashCode() ^ this.Message.GetHashCode();
            
            return this.Reason.GetHashCode() ^ this.Code.ToString().GetHashCode() ^ this.Message.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            UnaryTypeChange other = obj as UnaryTypeChange;

            if ((object)other == null)
            {
                return false;
            }

            return this.Reason == other.Reason
                    && this.Code == other.Code
                    && this.Message == other.Message;
        }

        public bool Equals(UnaryTypeChange other)
        {
            if ((object)other == null)
            {
                return false;
            }

            return this.Reason == other.Reason
                    && this.Code == other.Code
                    && this.Message == other.Message;
        }

        public static bool operator ==(UnaryTypeChange a, UnaryTypeChange b)
        {
            if (object.ReferenceEquals(a, b))
            {
                return true;
            }

            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }

            return a.Reason == b.Reason
                    && a.Code == b.Code
                    && a.Message == b.Message;
        }

        public static bool operator !=(UnaryTypeChange a, UnaryTypeChange b)
        {
            return !(a == b);
        }

    }
}
